package com.sunsharing.common.utils;

import java.util.Date;
import java.util.Map;
import java.lang.StringBuilder;

/**
 * <strong>可替换参数变量的字符串类。</strong>参数的形式为：${参数}<p/>
 * 例如：字符串 "This is a ${SomeThing}." 可替换的部分是：${SomeThing}。其中，SomeThing即为参数。<br/>
 * 如果要将${SomeThing}替换为字符串"Demo"（也就是说替换后的字符串是："This is a Demo."），
 * 我们可以将SomeThing和Demo组成键值对放入Map中进行转换。<p/>
 * 代码示例：<br/>
 * <pre>{@code
 *   String demoStr = "This is a ${SomeThing}.";
 *   DynamicString ds = new DynamicString(demoStr);
 *   Map<String,String> param = new java.util.HashMap<String,String>(4);
 *   param.put("SomeThing", "Demo");
 *   System.out.println(ds.convert(param));
 * }</pre>
 * <strong>注意：反斜杠'/'是转义字符，活用可处理常见问题。</strong>
 * <P>该类创建于 2010-3-3 上午01:06:26
 * @version 1.0.0
 * @author 侯磊
 */
public class DynamicString {

    private String dynStr;
    private DynamicPattern header;
    private DynamicPattern tail;

    static abstract class DynamicPattern {
        DynamicPattern next;
        public abstract Object subConvert(Map<String,?> pattern);
    }

    static class StringPattern extends DynamicPattern {
        private String pattern;

        public StringPattern(StringBuilder buff, int start, int end) {
            this.pattern = buff.substring(start, end);
        }
        @Override
        public Object subConvert(Map<String,? extends Object> map) {
            return pattern;
        }
    }

    static class MappedPattern extends DynamicPattern {
        private String key;

        public MappedPattern(StringBuilder buff, int start, int end) {
            this.key = buff.substring(start, end);
        }
        @Override
        public Object subConvert(Map<String,? extends Object> param) {
            if(param.get(key)==null){
                throw new IllegalArgumentException("所传入的Map中，不含有参数："+key);
            }
            return param.get(key);
        }
    }

    /**可替换参数变量的字符串类。该类适用于多个参数的情况。
     * @param dynStr 模板字符串。
     */
    public DynamicString(String dynStr) {
        this.dynStr = dynStr;
        init();
    }

    /**
     * 生成中间模板，转义字符也要考虑在内。
     */
    private void init() {
        header = tail = null;
        StringBuilder buff = new StringBuilder(dynStr);
        int start = 0, ptr = 0;
        boolean noMatching = true;
        for (ptr = start; ptr < buff.length(); ptr++) {
            if(buff.charAt(ptr)=='$' && buff.charAt(ptr+1)=='{'){
                if(ptr>0 && buff.charAt(ptr-1)=='/'){
                    buff.deleteCharAt(ptr---1);
                    if(ptr>1 && buff.charAt(ptr-1)=='/' && buff.charAt(ptr-2)=='/'){
                        buff.deleteCharAt(ptr---1);continue;
                    }
                    if(!(ptr>0 && buff.charAt(ptr-1)=='/'))
                        continue;
                }
                noMatching=false;
                StringPattern sp = new StringPattern(buff, start, ptr);
                appendPattern(sp);
                start = ptr+2;
                for (ptr += 2; ptr < buff.length(); ptr++) {
                    if (buff.charAt(ptr) == '}') {
                        if(buff.charAt(ptr-1)=='/'){
                            buff.deleteCharAt(ptr---1);
                            if(buff.charAt(ptr-1)!='/')
                                continue;
                        }
                        MappedPattern mp = new MappedPattern(buff, start, ptr);
                        appendPattern(mp);
                        noMatching=true;
                        start = ++ptr;break;
                    }
                }
            }
        }
        if (noMatching && ptr <= buff.length())
            appendPattern(new StringPattern(buff, start, ptr));
    }

    private DynamicString appendPattern(DynamicPattern pattern) {
        if (header == null) {
            header = pattern;
            tail = header;
        } else {
            tail.next = pattern;
            tail = pattern;
        }
        return this;
    }

    /**传入参数变量，得到替换后的结果。
     * @param param 将替换的参数及变量以键值对的形式存放到Map对象中。
     * @return  返回替换回的结果。
     * @exception IllegalArgumentException 当待替换的参数不在Map对象中时，抛出该异常。
     */
    public String convert(Map<String,? extends Object> param) {
        if (header == null)
            return null;
        DynamicPattern ptr = header;
        StringBuilder sb = new StringBuilder();
        while (ptr != null) {
            sb.append(ptr.subConvert(param));
            ptr = ptr.next;
        }
        return sb.toString();
    }

    /**
     * @see #convert(Map)
     */
    public String convert(String key,String value){
        Map<String,String> param = new java.util.HashMap<String,String>(2);
        param.put(key, value);
        return convert(param);
    }

    public static void main(String []a)
    {
        String demoStr = "This is a ${SomeThing}.";
        Date d = new Date();
        for(int i=0;i<1000;i++)
        {
           DynamicString ds = new DynamicString(demoStr);
           Map<String,String> param = new java.util.HashMap<String,String>(4);
           param.put("SomeThing", "Demo");
           ds.convert(param);
        }
        System.out.println(""+(new Date().getTime()-d.getTime()));
    }
}
